/**
 * Security utilities for model configuration management
 * Implements additional security measures for API key handling and data validation
 */

export class SecurityUtils {
  private static instance: SecurityUtils;
  private keyCache: Map<string, { encrypted: string; timestamp: number }> = new Map();
  private readonly CACHE_TTL = 5 * 60 * 1000; // 5 minutes

  static getInstance(): SecurityUtils {
    if (!SecurityUtils.instance) {
      SecurityUtils.instance = new SecurityUtils();
    }
    return SecurityUtils.instance;
  }

  /**
   * Enhanced XSS protection for input validation
   */
  sanitizeInput(input: string): string {
    return input
      .replace(/[<>'"&]/g, (char) => {
        const entities: Record<string, string> = {
          '<': '&lt;',
          '>': '&gt;',
          '"': '&quot;',
          "'": '&#x27;',
          '&': '&amp;'
        };
        return entities[char] || char;
      })
      .trim();
  }

  /**
   * Validate URL against whitelist patterns
   */
  validateApiUrl(url: string): { valid: boolean; error?: string } {
    const allowedPatterns = [
      /^https:\/\/api\.openai\.com\/v1/,
      /^https:\/\/api\.anthropic\.com/,
      /^https:\/\/api\.deepseek\.com/,
      /^https:\/\/[a-zA-Z0-9\-]+\.openai\.azure\.com/,
      /^https:\/\/anyrouter\.(top|ai)/, 
      /^http:\/\/localhost:\d+/, // Allow localhost for development
      /^https:\/\/[a-zA-Z0-9\-\.]+\.(com|net|org|ai|top)/, // General pattern for known domains
    ];

    if (!url || typeof url !== 'string') {
      return { valid: false, error: 'URL is required' };
    }

    try {
      const parsedUrl = new URL(url);
      
      // Check if URL uses HTTPS (except localhost)
      if (parsedUrl.protocol !== 'https:' && !parsedUrl.hostname.includes('localhost')) {
        return { valid: false, error: 'Only HTTPS URLs are allowed' };
      }

      // Check against allowed patterns
      const isAllowed = allowedPatterns.some(pattern => pattern.test(url));
      if (!isAllowed) {
        return { valid: false, error: 'URL not in allowed domains list' };
      }

      return { valid: true };
    } catch (error) {
      return { valid: false, error: 'Invalid URL format' };
    }
  }

  /**
   * Validate API key format based on provider
   */
  validateApiKeyFormat(provider: string, apiKey: string): { valid: boolean; error?: string } {
    if (!apiKey || typeof apiKey !== 'string') {
      return { valid: false, error: 'API key is required' };
    }

    const patterns: Record<string, RegExp> = {
      'openai': /^sk-[A-Za-z0-9\-_]{10,}$/,  // 放宽长度要求，允许测试密钥
      'claude': /^sk-ant-[A-Za-z0-9\-_]{10,}$/,  // 放宽长度要求
      'deepseek': /^sk-[A-Za-z0-9\-_]{10,}$/,  // 放宽长度要求
      'qwen': /^sk-[A-Za-z0-9\-_]{10,}$/,  // 放宽长度要求
      'custom': /^[A-Za-z0-9\-_]{8,}$/ // Generic pattern for custom providers
    };

    const pattern = patterns[provider.toLowerCase()] || patterns['custom'];
    
    if (!pattern.test(apiKey)) {
      return { valid: false, error: `Invalid API key format for ${provider}` };
    }

    // Check for obviously fake or test keys (暂时禁用，允许测试)
    // TODO: 在生产环境中重新启用此检查
    const suspiciousPatterns = [
      // /test/i,  // 暂时允许test
      /fake/i,
      /demo/i,
      /example/i,
      /placeholder/i,
      /^sk-000/,
      /^sk-111/,
      /^sk-aaa/
    ];

    if (suspiciousPatterns.some(pattern => pattern.test(apiKey))) {
      return { valid: false, error: 'API key appears to be a test or placeholder value' };
    }

    return { valid: true };
  }

  /**
   * Secure cache for temporary key storage
   */
  cacheEncryptedKey(keyId: string, encryptedKey: string): void {
    this.keyCache.set(keyId, {
      encrypted: encryptedKey,
      timestamp: Date.now()
    });

    // Clean up expired entries
    this.cleanupExpiredCache();
  }

  /**
   * Retrieve cached encrypted key
   */
  getCachedKey(keyId: string): string | null {
    const cached = this.keyCache.get(keyId);
    if (!cached) return null;

    // Check if expired
    if (Date.now() - cached.timestamp > this.CACHE_TTL) {
      this.keyCache.delete(keyId);
      return null;
    }

    return cached.encrypted;
  }

  /**
   * Clear all cached keys (for security)
   */
  clearKeyCache(): void {
    this.keyCache.clear();
  }

  /**
   * Clean up expired cache entries
   */
  private cleanupExpiredCache(): void {
    const now = Date.now();
    for (const [keyId, cached] of this.keyCache.entries()) {
      if (now - cached.timestamp > this.CACHE_TTL) {
        this.keyCache.delete(keyId);
      }
    }
  }

  /**
   * Generate secure random string for tokens
   */
  generateSecureToken(length: number = 32): string {
    const array = new Uint8Array(length);
    crypto.getRandomValues(array);
    return btoa(String.fromCharCode(...array))
      .replace(/[+/=]/g, (char) => {
        const replacements: Record<string, string> = { '+': '-', '/': '_', '=': '' };
        return replacements[char] || char;
      })
      .substring(0, length);
  }

  /**
   * Content Security Policy headers for API requests
   */
  getSecurityHeaders(): Record<string, string> {
    return {
      'Content-Security-Policy': "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'",
      'X-Content-Type-Options': 'nosniff',
      'X-Frame-Options': 'DENY',
      'X-XSS-Protection': '1; mode=block',
      'Referrer-Policy': 'strict-origin-when-cross-origin'
    };
  }

  /**
   * Audit log entry creation
   */
  createAuditLogEntry(action: string, configId: string, details?: any): {
    timestamp: Date;
    action: string;
    configId: string;
    userAgent: string;
    details?: any;
  } {
    return {
      timestamp: new Date(),
      action: this.sanitizeInput(action),
      configId: this.sanitizeInput(configId),
      userAgent: this.sanitizeInput(navigator.userAgent.substring(0, 200)),
      details: details ? this.sanitizeObject(details) : undefined
    };
  }

  /**
   * Recursively sanitize object properties
   */
  private sanitizeObject(obj: any): any {
    if (typeof obj === 'string') {
      return this.sanitizeInput(obj);
    }
    
    if (typeof obj !== 'object' || obj === null) {
      return obj;
    }

    if (Array.isArray(obj)) {
      return obj.map(item => this.sanitizeObject(item));
    }

    const sanitized: any = {};
    for (const [key, value] of Object.entries(obj)) {
      sanitized[this.sanitizeInput(key)] = this.sanitizeObject(value);
    }
    
    return sanitized;
  }

  /**
   * Check for suspicious activity patterns
   */
  detectSuspiciousActivity(events: any[]): { suspicious: boolean; reasons: string[] } {
    const reasons: string[] = [];
    const now = Date.now();
    const recentEvents = events.filter(e => now - new Date(e.timestamp).getTime() < 60000); // Last minute

    // Too many requests in short time
    if (recentEvents.length > 20) {
      reasons.push('Excessive API requests detected');
    }

    // Multiple failed validations
    const failedValidations = recentEvents.filter(e => e.action.includes('failed'));
    if (failedValidations.length > 5) {
      reasons.push('Multiple validation failures detected');
    }

    // Unusual user agent patterns
    const userAgents = new Set(recentEvents.map(e => e.userAgent));
    if (userAgents.size > 3) {
      reasons.push('Multiple user agents detected');
    }

    return {
      suspicious: reasons.length > 0,
      reasons
    };
  }
}

export default SecurityUtils.getInstance();